#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_log.h"

#include "RCS_protocol.h"
#include "RCS_ble_master.h"
#include "RCS_station.h"
#include "RCS_master.h"
#include "RCS_net.h"
/**
 * 基站扫描
 *
 * 应用层：
 *
 * 需要用链表保存，链表的第一个实际节点是head。没有 fake_head.
 *
 * 在删除节点时需要考虑是否是头节点。
 *
 * 更新时，需要遍历链表，计数-1. 如果超过就删除。
 */

typedef struct station_node_s
{
  int16_t avg_rssi;
  uint8_t count;
  uint32_t id;
  station_state_t st;
  struct station_node_s *next;
} station_node_t;

typedef struct station_list_s
{
  station_node_t *head;
  uint8_t item_num;
  SemaphoreHandle_t mutex;
} station_list_t;

#define NODE_COUNT_DEFAULT 4

const char station_name_table[STATION_CLASS_NUM][12] = {
    "DEFAULT",
    "RESOURCE",
    "SAFETY",
    "TEAM_A",
    "TEAM_B",
    "REBORN",
    "HP_DROP",
    "HP_CURE",
    "INVINCIBLE"};

static const char *TAG = "STA";
extern rcs_mast_system_t rcsSystem;
extern QueueHandle_t xGameQueue;
station_list_t station_list[STATION_CLASS_NUM];

static station_node_t *new_station_node(uint32_t id, int16_t rssi)
{
  station_node_t *node = calloc(1, sizeof(station_node_t));
  if (node == NULL)
  {
    return node;
  }
  node->avg_rssi = rssi;
  node->id = id;
  node->st = RISE_STA;
  node->count = NODE_COUNT_DEFAULT;
  node->next = NULL;
  return node;
}

uint8_t init_station_list(void)
{
  for (size_t i = 0; i < STATION_CLASS_NUM; i++)
  {
    station_list[i].mutex = xSemaphoreCreateMutex();
    if (station_list[i].mutex == NULL)
    {
      ESP_LOGE(TAG, "openMutex Create failed");
      return 1;
    }
    station_list[i].item_num = 0;
    station_list[i].head = NULL;
  }
  return 0;
}

// 在更新基站状态线程中调用。
uint8_t station_list_self_subtraction(station_type_t sta_idx)
{
  station_list_t *list = &station_list[sta_idx];

  if (list->item_num == 0 || list->head == NULL)
  {
    ESP_LOGV(TAG, "list[%d] is null. return", sta_idx);
    return 0;
  }

  station_node_t *cur_node = list->head;
  station_node_t *last_node = list->head;

  uint8_t node_idx = 0;
  while (cur_node != NULL)
  {
    uint8_t delete_flag = 0;
    // 业务处理;
    cur_node->count--;
    // ESP_LOGI(TAG, "list[%d] node[%d] rssi: %d", sta_idx, node_idx, cur_node->avg_rssi);
    node_idx++;
    ESP_LOGV(TAG, "list[%d] cur_node->count %d", sta_idx, cur_node->count);
    if (cur_node->count > 1)
    {
      cur_node->st = KEEP_HOLD_STA;
    }
    else if (cur_node->count == 1)
    {
      cur_node->st = DOWN_STA;
    }
    else if (cur_node->count == 0)
    {
      cur_node->st = KEEP_NO_STA;
      delete_flag = 1;
    }

    // 删除节点
    if (delete_flag)
    {
      ESP_LOGV(TAG, "list[%d] need to delete.", sta_idx);
      xSemaphoreTake(list->mutex, portMAX_DELAY);
      if (cur_node == list->head)
      {
        ESP_LOGV(TAG, "list[%d] delete head node", sta_idx);
        list->head = cur_node->next;
        free(cur_node);
        list->item_num--;
        cur_node = list->head;
        xSemaphoreGive(list->mutex);
      }
      else
      {
        ESP_LOGE(TAG, "list[%d] delete node", sta_idx);
        last_node->next = cur_node->next;
        free(cur_node);
        list->item_num--;
        // 给cur_node赋值，继续遍历
        cur_node = last_node->next;
        xSemaphoreGive(list->mutex);
      }
    }
    else
    {
      last_node = cur_node;
      cur_node = cur_node->next;
    }
  }
  return 0;
}

// 对于需要有多个成员的链表。在扫描回调函数里调用。
uint8_t append_to_station_list(station_type_t sta_idx, uint32_t id, int16_t rssi)
{
  ESP_LOGV(TAG, "list[%d] append node id: %" PRIu32 ".", sta_idx, id);
  station_list_t *list = &station_list[sta_idx];

  if (list->head == NULL)
  {
    ESP_LOGV(TAG, "list[%d] add new node in head.", sta_idx);
    xSemaphoreTake(list->mutex, portMAX_DELAY);
    list->head = new_station_node(id, rssi);
    list->item_num++;
    xSemaphoreGive(list->mutex);
    if (list->head == NULL)
    {
      // 创建新的错误
      ESP_LOGV(TAG, "list[%d] add new node error.", sta_idx);
      return 1;
    }
    else
    {
      ESP_LOGV(TAG, "list[%d] add new node success.", sta_idx);
      return 0;
    }
  }
  // 遍历 链表，如果有相同的id 就更新 rssi， 如果没有就加在后面。
  station_node_t *cur_node = list->head;
  while (cur_node->id != id && cur_node->next != NULL)
  {
    cur_node = cur_node->next;
  }
  if (cur_node->id == id)
  {
    // 发现了原有的节点。
    ESP_LOGV(TAG, "list[%d] found old node. update", sta_idx);
    cur_node->count = NODE_COUNT_DEFAULT;
    cur_node->st = KEEP_HOLD_STA;
    cur_node->avg_rssi = (cur_node->avg_rssi * 4 + rssi) / 5;
    return 0;
  }
  else
  {
    // 遍历结束也没有发现相同的ID，创建新节点
    ESP_LOGV(TAG, "list[%d] add new node in tail", sta_idx);
    xSemaphoreTake(list->mutex, portMAX_DELAY);
    cur_node->next = new_station_node(id, rssi);
    list->item_num++;
    xSemaphoreGive(list->mutex);
    if (cur_node->next == NULL)
    {
      // 创建新的节点失败
      return 1;
    }
    else
    {
      return 0;
    }
  }
  return 0;
}

// 对于只需要有一个成员的链表。在扫描回调函数里调用。
uint8_t replace_to_station_list(station_type_t sta_idx, uint32_t id, int16_t rssi)
{
  station_list_t *list = &station_list[sta_idx];
  if (list->head == NULL)
  {
    xSemaphoreTake(list->mutex, portMAX_DELAY);
    list->head = new_station_node(id, rssi);
    list->item_num++;
    xSemaphoreGive(list->mutex);
    if (list->head == NULL)
    {
      // 创建新的错误
      return 1;
    }
    else
    {
      return 0;
    }
  }
  else
  {
    station_node_t *cur_node = list->head;
    cur_node->id = id;
    cur_node->count = NODE_COUNT_DEFAULT;
    cur_node->st = KEEP_HOLD_STA;
    cur_node->avg_rssi = (cur_node->avg_rssi * 4 + rssi) / 5;
  }
  return 0;
}

void select_team_by_station(void)
{
  // jiasuo
  uint8_t command = 0;
  uint8_t team_a = 0;
  uint8_t team_b = 0;
  if (station_list[TEAM_A_STATION].head != NULL)
  {
    command = TEAM_A_STA_COMM;
    team_a = 1;
  }
  if (station_list[TEAM_B_STATION].head != NULL)
  {
    command = TEAM_B_STA_COMM;
    team_b = 1;
  }
  if (team_a && team_b)
  {
    if (station_list[TEAM_A_STATION].head->avg_rssi >
        station_list[TEAM_B_STATION].head->avg_rssi)
    {
      command = TEAM_A_STA_COMM;
    }
    else
    {
      command = TEAM_B_STA_COMM;
    }
    // ESP_LOGV(BLE_TAG, "sta A: %d, sta B: %d",
    //     station_array[TEAM_A_STATION].avg_rssi,
    //     station_array[TEAM_B_STATION].avg_rssi);
  }

  if (command != 0)
  {
    // PACKAGE_LEN_UPL_LEN + MESSAGE_TYPE_BATTERY_UPL_LEN + COMMAND_UPL_LEN = 10
    uint8_t package[10] = {0};
    make_prop_command_package(package, 10, command, rcsSystem.equip.core.battery);
    if (xQueueSend(xGameQueue, package, pdMS_TO_TICKS(200)) != pdPASS)
    {
      ESP_LOGE(TAG, "queue full.");
    }
    uint8_t package2[10] = {0};
    make_prop_command_package(package2, 10, START_GAME_COMM, rcsSystem.equip.core.battery);
    if (xQueueSend(xGameQueue, package2, pdMS_TO_TICKS(200)) != pdPASS)
    {
      ESP_LOGE(TAG, "queue full.");
    }
  }
  return;
}

void station_hp_handle(void)
{
  uint8_t command = 0;
  uint8_t cure_hp = 0;
  uint8_t drop_hp = 0;
  if (station_list[HP_CURE_STATION].head != NULL)
  {
    command = HP_CURE_STA_COMM;
    cure_hp = 1;
  }
  if (station_list[HP_DROP_STATION].head != NULL)
  {
    command = HP_DROP_STA_COMM;
    drop_hp = 1;
  }
  if (cure_hp && drop_hp)
  {
    if (station_list[HP_CURE_STATION].head->avg_rssi >
        station_list[HP_DROP_STATION].head->avg_rssi)
    {
      command = HP_CURE_STA_COMM;
    }
    else
    {
      command = HP_DROP_STA_COMM;
    }
    // ESP_LOGV(BLE_TAG, "HP cure: %d, drop: %d, command: %d",
    //     station_array[HP_CURE_STA_COMM].avg_rssi,
    //     station_array[HP_DROP_STA_COMM].avg_rssi, command);
  }
  if (command != 0)
  {
    // PACKAGE_LEN_UPL_LEN + MESSAGE_TYPE_BATTERY_UPL_LEN + COMMAND_UPL_LEN = 10
    uint8_t package[10] = {0};
    make_prop_command_package(package, 10, command, rcsSystem.equip.core.battery);
    if (xQueueSend(xGameQueue, package, pdMS_TO_TICKS(200)) != pdPASS)
    {
      ESP_LOGV(TAG, "queue full.");
    }
  }
  return;
}

static uint8_t is_in_selfteam_reborn_station(void)
{
  uint8_t res = 0;
  if (rcsSystem.game.player.team == 1 && station_list[TEAM_A_STATION].head != NULL)
  {
    res = 1;
  }
  else if (rcsSystem.game.player.team == 2 && station_list[TEAM_B_STATION].head != NULL)
  {
    res = 1;
  }
  return res;
}

void station_reborn_handle(void)
{
  if (station_list[REBORN_STATION].head == NULL)
  {
    return;
  }
  if (rcsSystem.game.player.living)
  {
    return;
  }
  // 2024.8.3
  // 分队点和复活点结合，如果死亡并处于自己队伍的分队点中，则复活。
  if (is_in_selfteam_reborn_station() == 0)
  {
    return;
  }
  // PACKAGE_LEN_UPL_LEN + MESSAGE_TYPE_BATTERY_UPL_LEN + COMMAND_UPL_LEN = 10
  uint8_t package[10] = {0};
  make_prop_command_package(package, 10, REBORN_P_STA_COMM, rcsSystem.equip.core.battery);
  if (xQueueSend(xGameQueue, package, pdMS_TO_TICKS(200)) != pdPASS)
  {
    ESP_LOGE(TAG, "queue full.");
  }
  return;
}

uint8_t period_upload_station(station_type_t sta_idx)
{
  station_list_t *list = &station_list[sta_idx];
  if (list->head == NULL || list->item_num == 0)
  {
    return 0;
  }

  station_node_t *cur_node = station_list[sta_idx].head;
  uint32_t param_arr[2] = {0};
  size_t message_length;
  while (cur_node != NULL)
  {
    ESP_LOGV(TAG, "list[%d] upload node.", sta_idx);
    param_arr[0] = STATION_UNKNOWN;
    param_arr[1] = cur_node->id;
    char *message = make_net_json_package(ERROR_NET_UP, &message_length, param_arr);
    if (message)
    {
      net_send(message, message_length);
      free(message);
    }
    else
    {
      ESP_LOGV("send", "error, calloc failed line: %d", __LINE__);
      return 1;
    }
    cur_node = cur_node->next;
  }
  return 0;
}

void station_invincible_handle(void)
{
  if (station_list[INVINCIBLE_STATION].head != NULL)
  {
    // PACKAGE_LEN_UPL_LEN + MESSAGE_TYPE_BATTERY_UPL_LEN + COMMAND_UPL_LEN = 10
    uint8_t package[10] = {0};
    make_prop_command_package(package, 10, INVINCIBLE_STA_COMM, rcsSystem.equip.core.battery);
    if (xQueueSend(xGameQueue, package, pdMS_TO_TICKS(200)) != pdPASS)
    {
      ESP_LOGE(TAG, "queue full.");
    }
  }
  return;
}
